#include "common.h"

// 创建线程池
ThreadPool *thread_pool_create(int thread_count, int queue_size)
{
    ThreadPool *pool = (ThreadPool *)malloc(sizeof(ThreadPool));
    if (pool == NULL)
    {
        perror("malloc thread pool failed");
        return NULL;
    } // 计算 ThreadPool 结构体的大小，并将这块内存的地址赋值给指针 pool

    // 初始化
    pool->thread_count = thread_count;
    pool->queue_size = queue_size;
    pool->head = pool->tail = pool->count = 0;
    pool->shutdown = 0;

    // 分配线程和任务队列
    pool->threads = (pthread_t *)malloc(sizeof(pthread_t) * thread_count);
    pool->queue = (ThreadPoolTask *)malloc(sizeof(ThreadPoolTask) * queue_size);

    // 初始化互斥锁和条件变量
    if (pthread_mutex_init(&(pool->lock), NULL) != 0 ||  // 尝试初始化一个互斥锁pool->lock。如果初始化失败（即返回值不为0），则进入错误处理代码块
        pthread_cond_init(&(pool->notify), NULL) != 0 || // 尝试初始化一个条件变量pool->notify。如果初始化失败，同样进入错误处理代码块
        pool->threads == NULL || pool->queue == NULL)
    { // 检查线程数组pool->threads和任务队列pool->queue是否已正确分配内存。如果任一为NULL，表示内存分配失败，进入错误处理代码块
        if (pool->threads)
            free(pool->threads); // 如果线程数组已分配，释放其内存
        if (pool->queue)
            free(pool->queue); // 如果任务队列已分配，释放其内存
        if (pool)
            free(pool); // 如果线程池结构体已分配，释放其内存
        return NULL;
    }

    // 创建工作线程
    // pthread_create 函数创建一个新的线程
    //&(pool->threads[i])：线程的标识符，用于存储新创建线程的句柄
    // NULL 表示使用默认属性
    // thread_pool_worker工作线程函数
    //(void *)pool传递给线程函数的参数，这里是线程池的指针
    for (int i = 0; i < thread_count; i++)
    {
        if (pthread_create(&(pool->threads[i]), NULL, thread_pool_worker, (void *)pool) != 0)
        {
            thread_pool_destroy(pool); // 线程创建失败调用 thread_pool_destroy 函数销毁已经创建的线程池，释放所有已分配的资源
            return NULL;               // 返回 NULL，表示创建线程池失败
        }
    }

    return pool; // 所有线程都成功创建，函数返回指向线程池结构体的指针，表示创建成功
}

// 添加任务到线程池
int thread_pool_add_task(ThreadPool *pool, void (*function)(void *), void *arg)
{
    if (pool == NULL || function == NULL)
    {
        return -1;
    } // 检查 pool 和 function 是否为 NULL。如果任一为 NULL，表示参数无效，函数返回 -1

    if (pthread_mutex_lock(&(pool->lock)) != 0)
    {
        return -1; // 尝试获取线程池的互斥锁。如果获取失败，返回 -1
    }

    // 队列已满
    if (pool->count == pool->queue_size)
    {
        pthread_mutex_unlock(&(pool->lock));
        return -1; // 检查任务队列是否已满。如果队列中的任务数量等于队列大小，释放互斥锁并返回 -1
    }

    // 添加到队列尾部
    pool->queue[pool->tail].function = function;      // 将任务函数添加到队列的尾部
    pool->queue[pool->tail].arg = arg;                // 将函数的参数添加到队列的尾部
    pool->tail = (pool->tail + 1) % pool->queue_size; // 更新队列尾部指针，使其指向下一个空闲位置
    pool->count++;                                    // 增加队列中的任务数量

    // 通知工作线程
    // 发送条件变量信号，通知至少一个等待的工作线程有新任务可用。如果发送信号失败，释放互斥锁并返回 -1
    if (pthread_cond_signal(&(pool->notify)) != 0)
    {
        pthread_mutex_unlock(&(pool->lock));
        return -1;
    }

    pthread_mutex_unlock(&(pool->lock)); ////释放互斥锁
    return 0;
}

// 销毁线程池
int thread_pool_destroy(ThreadPool *pool)
{
    if (pool == NULL)
    {
        return -1;
    }//检查传入的线程池指针是否为 NULL。如果是，表示参数无效，函数返回 -1

    if (pthread_mutex_lock(&(pool->lock)) != 0)
    {
        return -1;
    }//尝试获取线程池的互斥锁。如果获取失败，返回 -1

    pool->shutdown = 1;//设置线程池的关闭标志为 1，这将通知工作线程线程池即将关闭

    // 唤醒所有线程
    if (pthread_cond_broadcast(&(pool->notify)) != 0 ||
        pthread_mutex_unlock(&(pool->lock)) != 0)
    {
        return -1;
    }//发送条件变量广播信号，唤醒所有等待的工作线程，并释放互斥锁。如果发送信号或释放锁失败，返回 -1

    // 等待所有线程结束
    for (int i = 0; i < pool->thread_count; i++)
    {
        if (pthread_join(pool->threads[i], NULL) != 0)
        {
            return -1;
        }
    }//等待所有线程结束。使用 pthread_join 函数等待每个线程完成其执行。如果等待线程结束失败，返回 -1

    // 释放资源
    if (pool->threads)
        free(pool->threads);//释放线程数组的内存
    if (pool->queue)
        free(pool->queue);//释放任务队列的内存
    pthread_mutex_destroy(&(pool->lock));//销毁互斥锁
    pthread_cond_destroy(&(pool->notify));//销毁条件变量
    free(pool);//释放线程池结构体的内存

    return 0;
}

// 工作线程函数
void *thread_pool_worker(void *arg)
{
    ThreadPool *pool = (ThreadPool *)arg;//将传入的 void* 类型参数转换为 ThreadPool* 类型，这个参数是线程池的指针

    while (1)
    {
        pthread_mutex_lock(&(pool->lock));//获取线程池的互斥锁，以确保对任务队列的访问是线程安全的

        // 等待任务或关闭
        while (pool->count == 0 && !pool->shutdown)
        {
            pthread_cond_wait(&(pool->notify), &(pool->lock));
        }//如果任务队列为空且线程池未关闭，线程将等待条件变量。pthread_cond_wait 会释放互斥锁并阻塞当前线程，直到其他线程发送信号或广播


        // 关闭线程
        if (pool->shutdown)
        {
            pthread_mutex_unlock(&(pool->lock));
            pthread_exit(NULL);
        }//检查线程池是否需要关闭。如果需要关闭，释放互斥锁并退出线程

        // 获取任务
        ThreadPoolTask task = pool->queue[pool->head];//从任务队列的头部获取一个任务
        pool->head = (pool->head + 1) % pool->queue_size;//更新任务队列头部指针，使其指向下一个任务
        pool->count--;//减少任务队列中的任务数量

        pthread_mutex_unlock(&(pool->lock));//释放互斥锁

        // 执行任务
        (*(task.function))(task.arg);//执行获取到的任务。task.function 是任务函数指针，task.arg 是传递给任务函数的参数
    }

    return NULL;
}